//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

//#include <stdio.h>
#include <ddk.h>
#include <compoundChannel.h>
#include "serialTrans.h"
#include <serialio.h>

#if defined(_arm)
#define COM_PORT ComPort3
#else
#define COM_PORT ComPort1
#endif

#define SERIALCONTROL_SETCONFIG                    0x00020000

#define IO_SET_CONFIG_SERIAL_OPEN                  0x0171
#define IO_SET_CONFIG_SERIAL_CLOSE                 0x0172

static IDeviceDriver *g_pSerialDev = NULL;

static DzMutex g_serial_send_mutex;
static DzMutex g_serial_recv_mutex;

int SerialInitPort()
{
    MemoryBuf_<1> memBuf;
    ECode ec = DzFindService(
        L"device:serial1", (IInterface **)&(g_pSerialDev));
    if (FAILED(ec)) {
        kprintf("Can't find device:serial service!\n");
        return -1;
    }
    ec = g_pSerialDev->Control(SERIALCONTROL_SETCONFIG | IO_SET_CONFIG_SERIAL_OPEN, memBuf, NULL, NULL);
    if (FAILED(ec)) {
        kprintf("Can't open device:serial!\n");
        return -1;
    }

    SERIAL_INFO new_info;
    
    new_info.baud = NUM_SERIAL_BAUD_115200;
    new_info.stop = NUM_SERIAL_STOP_1;
    new_info.parity = NUM_SERIAL_PARITY_NONE;
    new_info.word_length = NUM_SERIAL_WORD_LENGTH_8;
    new_info.flags =
        NUM_SERIAL_FLOW_DSRDTR_RX |
        NUM_SERIAL_FLOW_DSRDTR_TX |
        NUM_SERIAL_FLOW_RTSCTS_RX |
        NUM_SERIAL_FLOW_DSRDTR_TX;
    MemoryBuf ezData((Byte*)&new_info, sizeof(new_info));
    g_pSerialDev->Control(
        SERIALCONTROL_SETCONFIG | IO_SET_CONFIG_SERIAL_INFO,
        ezData,
        NULL,
        NULL);

    Int32 blocking = TRUE;
    MemoryBuf ezBlocking((Byte*)&blocking, sizeof(blocking));
    g_pSerialDev->Control(
        SERIALCONTROL_SETCONFIG | IO_SET_CONFIG_READ_BLOCKING,
        ezBlocking,
        NULL,
        NULL);

    return 0;
}

/*
int SerialSendData(void* pData, int size, int *pSendSize)
{
    WaitResult wr;
    MemoryBuf memBuf((Byte*)pData, size);
    int nSendSize = 0;

    g_serial_send_mutex.Lock(&wr);
    ECode ec = g_pSerialDev->Write(0, memBuf, &nSendSize, NULL);
    g_serial_send_mutex.Unlock();

    if (FAILED(ec)) {
        kprintf("Write serial failed %d!\n", ec);
        return -1;
    }

    if (NULL != pSendSize) {
        *pSendSize = nSendSize;
    }

    return 0;
}
*/

int SerialReceiveData(void* pData, int size, int *pReceiveSize)
{
    WaitResult wr;
    ECode ec;
    MemoryBuf tempBuf((Byte *)pData, size);

    g_serial_recv_mutex.Lock(&wr);
    ec = g_pSerialDev->Read(0, size, &tempBuf, NULL);
    g_serial_recv_mutex.Unlock();
    if (FAILED(ec)) {
        kprintf("Cann't get serial data \n");
        return -1;
    }

    if (NULL != pReceiveSize) {
        *pReceiveSize = tempBuf.GetUsed();
    }

    return 0;
}

int SerialPutChar(char byte)
{
    if (BspWriteComPort(COM_PORT, (uint8_t)byte))
        return 0;

    return -1;
}

int SerialSendData(void *data, int size, int *sendSize)
{
    int send_count = 0;
    WaitResult wr;

    g_serial_send_mutex.Lock(&wr);
    if (WaitResult_OK != wr) {
        return -1;
    }

    while (send_count < size) {
        if (0 != SerialPutChar(((char *)data)[send_count++])) {
            g_serial_send_mutex.Unlock();
            return -1;
        }
    }

    g_serial_send_mutex.Unlock();

    if (NULL != sendSize) {
        *sendSize = send_count;
    }

    return 0;
}
